package com.guangfeng.yql.comm.netty;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.guangfeng.yql.comm.netty.initalizer.BaseInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOutboundInvoker;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;

@Component
@Slf4j
public class TextNettyServer implements ApplicationRunner, ApplicationListener<ContextClosedEvent> {


    private NettyConfig nettyConfig;

    @Autowired
    public void setNettyConfig(NettyConfig nettyConfig) {
        this.nettyConfig = nettyConfig;
    }

    private List<Channel> serverChannelList;

    @Override
    public void run(ApplicationArguments args) {
        if (CollUtil.isNotEmpty(nettyConfig.getList())) {
            serverChannelList = new ArrayList<>(nettyConfig.getList().size());
            ScheduledThreadPoolExecutor executor = ThreadUtil.createScheduledExecutor(nettyConfig.getList().size());
            nettyConfig.getList().forEach(nettyProperty -> executor.submit(() -> startNettyService(nettyProperty)));
        }
    }

    public void startNettyService(NettyProperty nettyProperty) {
        // 创建一个主线程组
        NioEventLoopGroup group = new NioEventLoopGroup();
        // 创建一个工作线程组
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {// 创建一个启动器
            ServerBootstrap bootstrap = new ServerBootstrap();
            log.info("netty start  ip  ： {}  port ： {}  handel : {}", nettyProperty.getIp(), nettyProperty.getPort(), nettyProperty.getHandler());
            bootstrap.group(group, workerGroup);
            bootstrap.channel(NioServerSocketChannel.class);
            bootstrap.localAddress(new InetSocketAddress(nettyProperty.getIp(), nettyProperty.getPort()));
            BaseInitializer<?> baseInitializer = SpringUtil.getBean(nettyProperty.getInit());
            baseInitializer.setNettyProperty(nettyProperty);
            bootstrap.childHandler(baseInitializer);
            Channel serverChannel = bootstrap.bind().sync().channel();
            serverChannelList.add(serverChannel);
            serverChannel.closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        if (CollUtil.isNotEmpty(serverChannelList)) {
            serverChannelList.forEach(ChannelOutboundInvoker::close);
        }
        log.info("netty 服务停止");
    }
}
